﻿using System;
using System.Globalization;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using BackgroundCopyManager;

namespace Klinkby.PodCaster.Model
{
    sealed class Bits
    {
        readonly uint lcid = (uint)CultureInfo.GetCultureInfo("en-Us").LCID;
        BackgroundCopyManagerClass _manager = new BackgroundCopyManagerClass();

        public Bits()
        {              
        }

        public Guid Download(IEnumerable<IDownloadInfo> files)
        {
            GUID jobId = default(GUID);
            Safe(() =>
            {
                IBackgroundCopyJob job;
                _manager.CreateJob(string.Empty, BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD, out jobId, out job);
                foreach(var file in files)
                    job.AddFile(file.RemoteUrl.AbsoluteUri, file.LocalFilePath);
                job.Resume();
            });
            return jobId.ToGuid();
        }

        public BG_JOB_STATE GetState(Guid jobId)
        {
            BG_JOB_STATE state = default(BG_JOB_STATE);
            GUID JOBID = jobId.ToGUID();
            Safe(() =>
            {
                IBackgroundCopyJob job;
                _manager.GetJob(ref JOBID, out job);
                job.GetState(out state);
            });
            return state;
        }

        public void Complete(Guid jobId)
        {
            GUID JOBID = jobId.ToGUID();
            Safe(() =>
            {
                IBackgroundCopyJob job;
                _manager.GetJob(ref JOBID, out job);
                job.Complete();
            });
        }

        public void ClearJobs()
        {
            Safe(() =>
            {
                IEnumBackgroundCopyJobs jobs;
                _manager.EnumJobs(0, out jobs);
                jobs.Reset();
                IBackgroundCopyJob job;
                uint fetched = 0;
                do
                {
                    jobs.Next(1, out job, ref fetched);
                    if (job != null)
                        job.Cancel();
                } while (fetched == 1);
            });
        }

        void Safe(Action command)
        {
            try
            {
                command();
            }
            catch (COMException e)
            {
                string errText;
                _manager.GetErrorDescription(e.ErrorCode, lcid, out errText);
                throw new BitsException(errText, e);
            }
        }
    }

    [Serializable]
    class BitsException : Exception
    {
        //public BitsException() { }
        //public BitsException(string message) : base(message) { }
        protected BitsException(SerializationInfo info, StreamingContext context) : base(info, context) { }
        public BitsException(string message, COMException innerException) : base(message, innerException) { }
    }

    static class GUIDEx
    {
        public static Guid ToGuid(this GUID guid)
        {
            return new Guid((int)guid.Data1, (short)guid.Data2, (short)guid.Data3, guid.Data4);
        }

        public static GUID ToGUID(this Guid guid)
        {
            
            using (var ms = new MemoryStream(guid.ToByteArray()))
            {
                var br = new BinaryReader(ms);
                return new GUID() {
                    Data1 = br.ReadUInt32(),
                    Data2 = br.ReadUInt16(),
                    Data3 = br.ReadUInt16(),
                    Data4 = br.ReadBytes(8),
                };
            }
        }

    }
}
